/**
 * Copyright (c) 2018-2023, NXOS Development Team
 * SPDX-License-Identifier: Apache-2.0
 * 
 * Contains: cache management
 * 
 * Change Logs:
 * Date           Author            Notes
 * 2023-08-15     JasonHu           Init
 */

#ifndef __MEM_CACHE__
#define __MEM_CACHE__

#include <nxos_mini.h>

#define NX_CACHE_ENABLED    1
#define NX_CACHE_DISABLED   0

struct NX_CacheOps
{
    /* dcache enable/disable */
    void (*dcacheEnable)(void);
    void (*dcacheDisable)(void);

    /* icache enable/disable */
    void (*icacheEnable)(void);
    void (*icacheDisable)(void);

    /* cache status */
    NX_U32 (*dcacheStatus)(void);
    NX_U32 (*icacheStatus)(void);

    /* cache size */
    NX_U32 (*dcacheLineSize)(void);
    NX_U32 (*icacheLineSize)(void);

    /* icache invalidate */
    void (*icacheInvalidateAll)(void);
    void (*icacheInvalidateLine)(void *addr);
    void (*icacheInvalidateRange)(void *addr, NX_Size len);

    /*  dcache invalidate */
    void (*dcacheInvalidateAll)(void);
    void (*dcacheInvalidateLine)(void *addr);
    void (*dcacheInvalidateRange)(void *addr, NX_Size len);
    /*  dcache flush */
    void (*dcacheFlushAll)(void);
    void (*dcacheFlushLine)(void *addr);
    void (*dcacheFlushRange)(void *addr, NX_Size len);
    /*  dcache flush and invalidate */
    void (*dcacheClearAll)(void);
    void (*dcacheClearLine)(void *addr);
    void (*dcacheClearRange)(void *addr, NX_Size len);

    /* dache flush icache invalidate */
    void (*dcacheFlushIcacheInvalidate)(void *addr, NX_Size len);
};

NX_INTERFACE NX_IMPORT struct NX_CacheOps NX_CacheOpsInterface;

NX_INLINE void NX_DcacheEnable(void)
{
    if (NX_CacheOpsInterface.dcacheEnable != NX_NULL)
    {
        NX_CacheOpsInterface.dcacheEnable();
    }
}

NX_INLINE void NX_DcacheDisable(void)
{
    if (NX_CacheOpsInterface.dcacheDisable != NX_NULL)
    {
        NX_CacheOpsInterface.dcacheDisable();
    }
}

NX_INLINE void NX_IcacheEnable(void)
{
    if (NX_CacheOpsInterface.icacheEnable != NX_NULL)
    {
        NX_CacheOpsInterface.icacheEnable();
    }
}

NX_INLINE void NX_IcacheDisable(void)
{
    if (NX_CacheOpsInterface.icacheDisable != NX_NULL)
    {
        NX_CacheOpsInterface.icacheDisable();
    }
}

NX_INLINE NX_U32 NX_DcacheStatus(void)
{
    if (NX_CacheOpsInterface.dcacheStatus != NX_NULL)
    {
        return NX_CacheOpsInterface.dcacheStatus();
    }
    return 0;
}

NX_INLINE NX_U32 NX_IcacheStatus(void)
{
    if (NX_CacheOpsInterface.icacheStatus != NX_NULL)
    {
        return NX_CacheOpsInterface.icacheStatus();
    }
    return 0;
}

NX_INLINE NX_U32 NX_DcacheLineSize(void)
{
    if (NX_CacheOpsInterface.dcacheLineSize != NX_NULL)
    {
        return NX_CacheOpsInterface.dcacheLineSize();
    }
    return 0;
}

NX_INLINE NX_U32 NX_IcacheLineSize(void)
{
    if (NX_CacheOpsInterface.icacheLineSize != NX_NULL)
    {
        return NX_CacheOpsInterface.icacheLineSize();
    }
    return 0;
}

NX_INLINE void NX_IcacheInvalidateAll(void)
{
    if (NX_CacheOpsInterface.icacheInvalidateAll != NX_NULL)
    {
        NX_CacheOpsInterface.icacheInvalidateAll();
    }
}

NX_INLINE void NX_IcacheInvalidateLine(void *addr)
{
    if (NX_CacheOpsInterface.icacheInvalidateLine != NX_NULL)
    {
        NX_CacheOpsInterface.icacheInvalidateLine(addr);
    }
}

NX_INLINE void NX_IcacheInvalidateRange(void *addr, NX_Size len)
{
    if (NX_CacheOpsInterface.icacheInvalidateRange != NX_NULL)
    {
        NX_CacheOpsInterface.icacheInvalidateRange(addr, len);
    }
}

NX_INLINE void NX_DcacheInvalidateAll(void)
{
    if (NX_CacheOpsInterface.dcacheInvalidateAll != NX_NULL)
    {
        NX_CacheOpsInterface.dcacheInvalidateAll();
    }
}

NX_INLINE void NX_DcacheInvalidateLine(void *addr)
{
    if (NX_CacheOpsInterface.dcacheInvalidateLine != NX_NULL)
    {
        NX_CacheOpsInterface.dcacheInvalidateLine(addr);
    }
}

NX_INLINE void NX_DcacheInvalidateRange(void *addr, NX_Size len)
{
    if (NX_CacheOpsInterface.dcacheInvalidateRange != NX_NULL)
    {
        NX_CacheOpsInterface.dcacheInvalidateRange(addr, len);
    }
}

NX_INLINE void NX_DcacheFlushAll(void)
{
    if (NX_CacheOpsInterface.dcacheFlushAll != NX_NULL)
    {
        NX_CacheOpsInterface.dcacheFlushAll();
    }
}

NX_INLINE void NX_DcacheFlushLine(void *addr)
{
    if (NX_CacheOpsInterface.dcacheFlushLine != NX_NULL)
    {
        NX_CacheOpsInterface.dcacheFlushLine(addr);
    }
}

NX_INLINE void NX_DcacheFlushRange(void *addr, NX_Size len)
{
    if (NX_CacheOpsInterface.dcacheFlushRange != NX_NULL)
    {
        NX_CacheOpsInterface.dcacheFlushRange(addr, len);
    }
}

NX_INLINE void NX_DcacheClearAll(void)
{
    if (NX_CacheOpsInterface.dcacheClearAll != NX_NULL)
    {
        NX_CacheOpsInterface.dcacheClearAll();
    }
}

NX_INLINE void NX_DcacheClearLine(void *addr)
{
    if (NX_CacheOpsInterface.dcacheClearLine != NX_NULL)
    {
        NX_CacheOpsInterface.dcacheClearLine(addr);
    }
}

NX_INLINE void NX_DcacheClearRange(void *addr, NX_Size len)
{
    if (NX_CacheOpsInterface.dcacheClearRange != NX_NULL)
    {
        NX_CacheOpsInterface.dcacheClearRange(addr, len);
    }
}

NX_INLINE void NX_DcacheFlushIcacheInvalidate(void *addr, NX_Size len)
{
    if (NX_CacheOpsInterface.dcacheFlushIcacheInvalidate != NX_NULL)
    {
        NX_CacheOpsInterface.dcacheFlushIcacheInvalidate(addr, len);
    }
}

void NX_CacheInfoShow(void);

#endif /* __MEM_CACHE__ */
